package org.wheel.plugins.toolkit.sql.function;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import org.wheel.plugins.toolkit.sql.core.AbstractSegment;
import org.wheel.plugins.toolkit.sql.core.AbstractWrapper;
import org.wheel.plugins.toolkit.sql.core.GlobalConfig;
import org.wheel.plugins.toolkit.sql.core.SqlSegment;
import org.wheel.plugins.toolkit.sql.enums.Dialect;
import org.wheel.plugins.toolkit.sql.enums.SqlTimeUnit;
import org.wheel.plugins.toolkit.sql.helper.LambdaUtils;
import org.wheel.plugins.toolkit.sql.helper.SFunction;
import org.wheel.plugins.toolkit.sql.plugin.FunctionPlugin;
import org.wheel.plugins.toolkit.sql.segment.SqlWindowUnit;
import org.wheel.plugins.toolkit.sql.spi.PluginLoader;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 函数链式构造器 – 支持字符串/Lambda双写法
 */
public final class FunctionBuilder extends AbstractSegment {


    @Getter
    private final String funcName;           // 函数名，如：SUM
    private final boolean usePlugin;         // 是否走插件
    private final List<SqlSegment> args = CollUtil.newArrayList();

    private boolean distinct;

    private SqlWindowUnit over;              // OVER 子句

    // 对于函数参数比较，例如：SUM(t.amount) > 1000 需要延迟处理
    private String delayedOp;     // 例如 ">"
    private Object delayedValue;  // 比较值

    private boolean hasColumnAlias = false;

    private String columnAliasStr;

    /* ========== 工厂入口 ========== */
    /**
     * 需要延迟加载，允许在初始化时为null，但是后面需要执行bind方法，将函数参数绑定到wrapper中
     * @param funcName
     * @return
     */
    public static FunctionBuilder fn(String funcName){
        return fn(funcName, null);
    }
    public static FunctionBuilder fn(String funcName, AbstractWrapper<?, ?> wrapper) {
        return new FunctionBuilder(funcName, wrapper);
    }
    /**
     *  ========== 插件入口 ==========
     */
    public static FunctionBuilder plugin(String pluginKey, AbstractWrapper<?, ?> wrapper) {
        return new FunctionBuilder(pluginKey, true, wrapper);
    }


    /* ========== 构造函数 ========== */
    private FunctionBuilder(String funcName, AbstractWrapper<?, ?> wrapper) {
        this(funcName, false, wrapper);
    }
    // 插件模式不存 raw，仅存 funcName 2个参数互斥
    private FunctionBuilder(String funcName, boolean usePlugin, AbstractWrapper<?, ?> wrapper) {
        this.funcName = funcName;
        this.usePlugin = usePlugin;
        this.currentWrapper = wrapper;
    }

    /** 绑定 Wrapper */
    public FunctionBuilder bind(AbstractWrapper<?, ?> wrapper) {
        this.currentWrapper = wrapper;
        return this;
    }
    /**
     * 转成 SqlSegment 供 select 使用
     */
    public SqlSegment toSegment() {
        return this;   // 自己就是 SqlSegment 的实现类
    }

    /* ========== 链式参数 ========== */
    public FunctionBuilder distinct(boolean on) {
        this.distinct = on;   // 新增字段
        return this;
    }

    public FunctionBuilder tableAlias(String tableAlias){
        this.setTableAlias(tableAlias);
        return this;
    }

    public FunctionBuilder col(String column) {
//        args.add(() -> currentWrapper==null?column:StrUtil.join(".", currentWrapper.getMainAlias(), column));
        args.add(()->column);
        return this;
    }

    public FunctionBuilder col(SqlSegment column){
        args.add(column);
        return this;
    }

    public FunctionBuilder col(SFunction<?, ?> column){
        if(column != null) {
            if (StrUtil.isBlank(this.getTableAlias())) {
                Class<?> tableEntityClass = LambdaUtils.getCapturingClass(column);
                this.setTableEntityClass(tableEntityClass);
            }
            this.col(LambdaUtils.getColumn(column));
        }
        return this;
    }
    public FunctionBuilder col(String tableAlias, SFunction<?, ?> column){
        this.setTableAlias(tableAlias);
        this.col(LambdaUtils.getColumn(column)).as(LambdaUtils.getFieldName(column));
        return this;
    }

    public FunctionBuilder arg(Object... literal) {
//        if(this.usePlugin) {
//            args.add(literal::toString);
//        }else{
//            args.add(() -> StrUtil.format(":param{}", literal));
//        }
//        String key = ParamBank.current().nextParam(literal);
//        args.add(() -> ":" + key);

//        args.add(literal::toString);

        String column = Stream.of( literal).map(Object::toString).collect(Collectors.joining(", "));
        args.add(()->column);
        return this;
    }

    public FunctionBuilder col(SqlTimeUnit unit) {
        args.add(unit::name);
        return this;
    }

    public FunctionBuilder over(Consumer<SqlWindowUnit> consumer) {
        if(currentWrapper != null) {
            this.over = new SqlWindowUnit(currentWrapper);
            consumer.accept(over);
        }
        return this;
    }

    public <T> FunctionBuilder as(SFunction<T, ?> columnAlias) {
        String alias = LambdaUtils.getFieldName(columnAlias);
        return as(alias);
    }

    public FunctionBuilder as(String columnAlias) {
        this.hasColumnAlias = true;
        this.columnAliasStr = columnAlias;
        return this;
    }

    /* ---------- 新增：比较运算符链 ---------- */
    public FunctionBuilder gt(Object value) { return compare(">", value); }
    public FunctionBuilder ge(Object value) { return compare(">=", value); }
    public FunctionBuilder lt(Object value) { return compare("<", value); }
    public FunctionBuilder le(Object value) { return compare("<=", value); }
    public FunctionBuilder eq(Object value) { return compare("=", value); }
    public FunctionBuilder ne(Object value) { return compare("<>", value); }

    /** 通用比较模板：函数 + 运算符 + 占位符 */
    private FunctionBuilder compare(String op, Object value) {
        // 延迟处理
        this.delayedOp = op;
        this.delayedValue = value;
        return this;   // 链式继续，不立即渲染
    }


    /* ========== 渲染 ========== */
    @Override
    public String getSql() {

        // 1. 先生成基础函数 SQL（此时 wrapper 已绑定）
        String funcSql = buildFunctionOnly();   // 新提取方法，见下

        // 2. 如果有延迟比较，再追加运算符 + 占位符
        if (delayedOp != null) {
            String paramKey = this.currentWrapper.getContext().getParamBank().current().nextParam(delayedValue);
            funcSql += " " + delayedOp + " :" + paramKey;
        }

        // 3. 继续处理 OVER、AS 别名
        if (over != null) {
            funcSql += over.getSql();
        }
        if (hasColumnAlias && StrUtil.isNotBlank(columnAliasStr)) {
            funcSql += " AS " + columnAliasStr;
        }

        return funcSql;
    }

    /**
     * 仅生成函数 SQL
     * @return
     */
    private String buildFunctionOnly() {
        // 1. 收集所有参数 SQL
        List<String> argSql = getColumnSegments();

        if(CollUtil.isEmpty(argSql) && this.distinct){
            return funcName;
        }
        if (usePlugin) {
            // 2. 通过 SPI 拿到插件
            FunctionPlugin plugin = PluginLoader.getInstance()
                    .getFunction(funcName);
            // 3. 交给插件生成方言 SQL
            Dialect dialect = currentWrapper==null? GlobalConfig.getDialect() :currentWrapper.getDialect();
            return plugin.toSql(argSql, dialect);
        }
        return funcName + '(' + (this.distinct?"DISTINCT ":"") + String.join(",", argSql) + ')';
    }

    /**
     * 获取所有带别名的字段
     * @return 带别名的字段字符串集合
     */
    private List<String> getColumnSegments(){
        return args.stream().map(s-> {
            String column = s.getSql();
            if(!column.contains(".") && (StrUtil.isNotBlank(this.getTableAlias()) || this.getTableEntityClass() != null)){
                String tableAlias = calcTableAlias();
                if(StrUtil.isNotBlank(tableAlias)) {
                    column = tableAlias + "." + column;
                }
            }
            return column;
        }).toList();
    }

//    private String calcTableAlias(){
//        String alias = null;
//        if(StrUtil.isNotBlank(this.getTableAlias())){
//            alias = this.getTableAlias(); // 优先自定义别名
//        }else if(this.currentWrapper != null && this.getTableEntityClass() != null){
//            // ① 反序列化拿实体类
//            Class<?> lambdaEntity = this.getTableEntityClass();
//            // ② 拿当前 Wrapper 的实体类
//            Class<?> wrapperEntity = this.currentWrapper.getEntityClass();
//            // ③ 类型一致才继续，否则打印日志
//            if (!lambdaEntity.getName().equals(wrapperEntity.getName())) {
//                log.warn("Lambda 字段所属实体 [{}] 与当前 Wrapper 实体 [{}] 不一致",
//                        lambdaEntity.getName(), wrapperEntity.getName());
//                alias = AliasRegistry.getInstance().resolveAlias(lambdaEntity, -1);
//            } else {
//              alias = this.currentWrapper.getMainAlias();
//            }
//        }else if(AliasRegistry.getInstance().isRegister(this.getTableEntityClass())) {
//            alias = AliasRegistry.getInstance().resolveAlias(this.getTableEntityClass(), -1);
//        }
//        return alias;
//    }
}